package com.xzy.spring.demo.aspect;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;
import java.util.Collections;

/**
 * @author xzy
 * @date 2021/2/18 21:51
 * 说明：需要通过@Aspect注解告诉Spring当前类是一个“切面类”。
 * Spring切面可以应用5种类型得通知：前置通知、后置通知、返回通知、异常通知、环绕通知。
 */
@Aspect
public class MathLog {

    /**
     * 公共的切入点表达式
     * 如果是在当前类内使用：可以使用简单方法名（pointCut()），也可以使用完整方法名（xxx.xxx.xxx.MathLog.pointCut()）
     * 如果是在当前类外使用：只能使用完整方法名
     */
    @Pointcut(value = "execution(public int com.xzy.spring.demo.aspect.MathUtil.*(..))")
    public void pointCut() {
    }

    /**
     * 1.通过简短方法名使用公共切点表达式
     * 2.通过JoinPoint获取连接点信息。JoinPoint必须放在参数列表最前面的位置！
     */
    @Before(value = "pointCut()")
    public void beforeStart(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println("切面通知：" + joinPoint.getSignature().getName() + "方法开始执行，参数列表：" + Arrays.toString(args));
    }

    /**
     * 1.通过完整方法名使用公共切点表达式
     * 2.通过JoinPoint获取连接点信息。JoinPoint必须放在参数列表最前面的位置！
     */
    @After(value = "com.xzy.spring.demo.aspect.MathLog.pointCut()")
    public void afterComplete(JoinPoint joinPoint) {
        System.out.println("切面通知：" + joinPoint.getSignature().getName() + "方法执行完成\n");
    }

    /**
     * 1.直接指定切点表达式
     * 2.通过JoinPoint获取连接点信息。JoinPoint必须放在参数列表最前面的位置！
     * 3.通过returning获取方法返回值
     */
    @AfterReturning(value = "execution(public int com.xzy.spring.demo.aspect.MathUtil.*(..))", returning = "returning")
    public void afterReturning(JoinPoint joinPoint, Object returning) {
        System.out.println("切面通知：" + joinPoint.getSignature().getName() + "方法返回数据：" + returning);
    }

    /**
     * 1.通过简短方法名使用公共切点表达式
     * 2.通过JoinPoint获取连接点信息。JoinPoint必须放在参数列表最前面的位置！
     * 3.通过returning获取方法抛出的异常
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void afterThrowing(JoinPoint joinPoint, Exception exception) {
        System.out.println("切面通知：" + joinPoint.getSignature().getName() + "方法抛出异常：" + exception);
    }
}
